package com.xiaoq;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import com.xiaoq.coms.FrameworkErrorCode;
import com.xiaoq.coms.util.JsonUtil;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;

public class JWTTokenAuthenFilter extends OncePerRequestFilter {
	private static List<String> NO_AUTH_ROUTES = new ArrayList<>();
	private static final String JWT_KEY = "lifestyle365-secret-201611120-20191119";
	private static Logger logger = LoggerFactory.getLogger(JWTTokenAuthenFilter.class);

	static {
		NO_AUTH_ROUTES.add("/api/v1/user/anonymous");
		NO_AUTH_ROUTES.add("/api/v1/user/reg_by_mobile");
		NO_AUTH_ROUTES.add("/api/v1/user/login_by_passwd");
		NO_AUTH_ROUTES.add("/api/v1/user/login_by_smscode");
		NO_AUTH_ROUTES.add("/api/v1/user/login_by_third_acc");
		NO_AUTH_ROUTES.add("/api/v1/user/vcode");
		NO_AUTH_ROUTES.add("/api/v1/user/%7BuserId%7D/supplementaryinfo_from_thirdapp");
		NO_AUTH_ROUTES.add("/api/v1/user/info/%7BuserId%7D");
		NO_AUTH_ROUTES.add("/api/v1/user/generateToken4test");
		NO_AUTH_ROUTES.add("/api/v1/zonemaster/reptileZone");
		NO_AUTH_ROUTES.add("/api/v1/sites/shop_food/reptile");
		NO_AUTH_ROUTES.add("/api/v1/sites/feature/comment");
		NO_AUTH_ROUTES.add("/api/v1/termver");
		NO_AUTH_ROUTES.add("/api/v1/sites/reptiles");
		NO_AUTH_ROUTES.add("/api/v1/sites/feature/comment/reptile");
		NO_AUTH_ROUTES.add("/api/v1/sites_point/reptiles");
		NO_AUTH_ROUTES.add("/api/v1/sites/entry");
		NO_AUTH_ROUTES.add("/api/v1/sites/toilet");
		NO_AUTH_ROUTES.add("/api/v1/pointar");
		NO_AUTH_ROUTES.add("/api/v1/merchant/verify");
		NO_AUTH_ROUTES.add("/api/v1/parking/reptile");
		NO_AUTH_ROUTES.add("/api/download_app/download");
		if (logger.isDebugEnabled()) {
			for (String url : NO_AUTH_ROUTES) {
				logger.debug("add NO_AUTH ROUTE, " + url);
			}
		}
	}


	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		// 没有取得授权前,服务器端将需要验证的信息赋值给request header中authentication位
		String authenticationHeader = request.getHeader("authentication"); // 放置需要验证的信息
		// 客户端发起请求时,将JWT赋值给request header中的authorization位
		String authorizationHeader = request.getHeader("authorization");
		String route = request.getRequestURI();
		// no auth route matching
		boolean needsAuthentication = true;

		if (NO_AUTH_ROUTES.contains(route)) {
			needsAuthentication = false;
		}
		// 如果是发送验证码的请求API则放行
		if (route.contains("verificationcode")) {
			needsAuthentication = false;
		}	
		if (needsAuthentication) {
			// Check for authorization header presence
			String authHeader;
			if (authorizationHeader == null || authorizationHeader.equalsIgnoreCase("")) {
				if (authenticationHeader == null || authenticationHeader.equalsIgnoreCase("")) {
					authHeader = null;
				} else {
					authHeader = authenticationHeader;
				}
			} else {
				authHeader = authorizationHeader;
			}

			if ("".equals(authHeader) || authHeader == null) {
				request.setAttribute("rc", FrameworkErrorCode.MISSING_AUTH_HEADER.value());
				request.setAttribute("msg", FrameworkErrorCode.MISSING_AUTH_HEADER.errorMsg);
				request.getRequestDispatcher("/api/v1/token_exception").forward(request, response);
			}

			if (authHeader != null && !authHeader.startsWith("Bearer ")) {
				request.setAttribute("rc", FrameworkErrorCode.INVALID_ACCESS_TOKEN_TYPE.value());
				request.setAttribute("msg", FrameworkErrorCode.INVALID_ACCESS_TOKEN_TYPE.errorMsg);
				request.getRequestDispatcher("/api/v1/token_exception").forward(request, response);
			}

			if (authHeader != null && authHeader.startsWith("Bearer ")) {
				String access_token = authHeader.substring(7); // The part after "Bearer "
				try {

					final Claims claims = Jwts.parser().setSigningKey(JWT_KEY).parseClaimsJws(access_token).getBody();
					if (logger.isDebugEnabled()) {
						logger.debug("claims --> " + JsonUtil.asString(claims));
					}
					String userId = claims.get("userId").toString();

					request.setAttribute("userId", userId);
					if (route.contains("%7B")) {
						route = route.replace("%7BuserId%7D", userId);
						request.getRequestDispatcher(route).forward(request, response);
					}else if(route.contains("%257B")){
						route = route.replace("%257BuserId%257D", userId);
						request.getRequestDispatcher(route).forward(request, response);;
					}else {
						filterChain.doFilter(request, response);
					}
				} catch (ExpiredJwtException expEx) {// 如果access_token过期
					expEx.printStackTrace();
					request.setAttribute("rc", FrameworkErrorCode.ACCESS_TOKEN_EXPIRED.value());
					request.setAttribute("msg",
							FrameworkErrorCode.ACCESS_TOKEN_EXPIRED.errorMsg + ": " + expEx.getMessage());
					request.getRequestDispatcher("/api/v1/token_exception").forward(request, response);
				} catch (UnsupportedJwtException | MalformedJwtException | IllegalArgumentException
						| SignatureException otherEx) {
					otherEx.printStackTrace();
					request.setAttribute("rc", FrameworkErrorCode.INVALID_ACCESS_TOKEN.value());
					request.setAttribute("msg",
							FrameworkErrorCode.INVALID_ACCESS_TOKEN.errorMsg + ": " + otherEx.getMessage());
					request.getRequestDispatcher("/api/v1/token_exception").forward(request, response);
				}
			}
		} else {
			filterChain.doFilter(request, response);
		}
	}
}